package com.weijian.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weijian.config.SocialRedisConfig;
import com.weijian.dal.entity.CourseLike;
import com.weijian.dal.entity.User;
import com.weijian.dal.entity.UserFollow;
import com.weijian.dal.mapper.CourseLikeMapper;
import com.weijian.dal.mapper.UserFollowMapper;
import com.weijian.dal.mapper.UserMapper;
import com.weijian.dal.dto.social.FollowUserDTO;
import com.weijian.dal.dto.social.UserStatsDTO;
import com.weijian.service.SocialService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 社交功能服务实现类
 * 基于MyBatis Plus和Redis Set实现用户关注和课程点赞功能
 */
@Slf4j
@Service
public class SocialServiceImpl extends ServiceImpl<UserFollowMapper, UserFollow> implements SocialService {

    @Resource
    private UserFollowMapper userFollowMapper;

    @Resource
    private CourseLikeMapper courseLikeMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private RedisTemplate<String, Object> socialRedisTemplate;

    @Resource
    private StringRedisTemplate socialStringRedisTemplate;

    @Resource
    private RedisTemplate<String, String> stringRedisTemplate;

    // ==================== 用户关注功能 ====================

    /**
     * 用户关注其他用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean followUser(Long currentUserId, Long targetUserId) {
        if (currentUserId.equals(targetUserId)) {
            throw new IllegalArgumentException("不能关注自己");
        }

        // 使用MyBatis Plus LambdaQueryWrapper检查是否已关注
        long count = this.lambdaQuery()
                .eq(UserFollow::getFollowerId, currentUserId)
                .eq(UserFollow::getFollowingId, targetUserId)
                .eq(UserFollow::getDeleted, 0)
                .count();

        if (count > 0) {
            return false;
        }

        try {
            // 1. 保存到数据库（使用MyBatis Plus的save方法）
            UserFollow follow = UserFollow.builder()
                    .followerId(currentUserId)
                    .followingId(targetUserId)
                    .creator(currentUserId)
                    .updater(currentUserId)
                    .build();
            this.save(follow);

            // 2. 更新Redis中的关注关系
            updateRedisFollowRelation(currentUserId, targetUserId, true);

            // 3. 更新计数器
            updateFollowCount(currentUserId, targetUserId, 1);

            // 4. 更新排行榜
            updateFollowingLeaderboard(currentUserId);

            // 5. 检查是否互相关注
            if (isFollowing(targetUserId, currentUserId)) {
                updateMutualFriends(currentUserId, targetUserId);
            }

            return true;
        } catch (Exception e) {
            log.error("关注用户失败: {} -> {}", currentUserId, targetUserId, e);
            throw new RuntimeException("关注失败，请稍后重试");
        }
    }

    /**
     * 用户取消关注其他用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean unfollowUser(Long currentUserId, Long targetUserId) {
        // 使用MyBatis Plus LambdaQueryWrapper查找关注记录
        UserFollow follow = this.lambdaQuery()
                .eq(UserFollow::getFollowerId, currentUserId)
                .eq(UserFollow::getFollowingId, targetUserId)
                .eq(UserFollow::getDeleted, 0)
                .one();

        if (follow == null) {
            return false;
        }

        try {
            // 1. 使用MyBatis Plus的updateById进行逻辑删除
            follow.setDeleted(1);
            follow.setUpdater(currentUserId);
            this.updateById(follow);

            // 2. 更新Redis中的关注关系
            updateRedisFollowRelation(currentUserId, targetUserId, false);

            // 3. 更新计数器
            updateFollowCount(currentUserId, targetUserId, -1);

            // 4. 更新排行榜
            updateFollowingLeaderboard(currentUserId);

            // 5. 更新共同好友缓存
            removeMutualFriend(currentUserId, targetUserId);

            return true;
        } catch (Exception e) {
            log.error("取消关注用户失败: {} -> {}", currentUserId, targetUserId, e);
            throw new RuntimeException("取消关注失败，请稍后重试");
        }
    }

    @Override
    public IPage<FollowUserDTO> getFollowingList(Long userId, IPage<FollowUserDTO> page) {
        // 使用MyBatis Plus的分页查询
        IPage<UserFollow> followPage = new Page<>(page.getCurrent(), page.getSize());

        followPage = this.lambdaQuery()
                .eq(UserFollow::getFollowerId, userId)
                .eq(UserFollow::getDeleted, 0)
                .orderByDesc(UserFollow::getCreateTime)
                .page(followPage);

        if (followPage.getRecords().isEmpty()) {
            return new Page<>(page.getCurrent(), page.getSize());
        }

        // 获取被关注用户信息
        List<Long> followingIds = followPage.getRecords().stream()
                .map(UserFollow::getFollowingId)
                .collect(Collectors.toList());

        List<User> users = userMapper.selectBatchIds(followingIds);
        Map<Long, User> userMap = users.stream()
                .collect(Collectors.toMap(User::getId, user -> user));

        List<FollowUserDTO> followUsers = followPage.getRecords().stream()
                .map(follow -> {
                    User user = userMap.get(follow.getFollowingId());
                    return convertToFollowUserDTO(user, follow);
                })
                .collect(Collectors.toList());

        IPage<FollowUserDTO> resultPage = new Page<>(page.getCurrent(), page.getSize(), followPage.getTotal());
        resultPage.setRecords(followUsers);
        return resultPage;
    }

    @Override
    public IPage<FollowUserDTO> getFollowersList(Long userId, IPage<FollowUserDTO> page) {
        // 使用MyBatis Plus的分页查询
        IPage<UserFollow> followPage = new Page<>(page.getCurrent(), page.getSize());

        followPage = this.lambdaQuery()
                .eq(UserFollow::getFollowingId, userId)
                .eq(UserFollow::getDeleted, 0)
                .orderByDesc(UserFollow::getCreateTime)
                .page(followPage);

        if (followPage.getRecords().isEmpty()) {
            return new Page<>(page.getCurrent(), page.getSize());
        }

        // 获取粉丝用户信息
        List<Long> followerIds = followPage.getRecords().stream()
                .map(UserFollow::getFollowerId)
                .collect(Collectors.toList());

        List<User> users = userMapper.selectBatchIds(followerIds);
        Map<Long, User> userMap = users.stream()
                .collect(Collectors.toMap(User::getId, user -> user));

        List<FollowUserDTO> followUsers = followPage.getRecords().stream()
                .map(follow -> {
                    User user = userMap.get(follow.getFollowerId());
                    return convertToFollowUserDTO(user, follow);
                })
                .collect(Collectors.toList());

        IPage<FollowUserDTO> resultPage = new Page<>(page.getCurrent(), page.getSize(), followPage.getTotal());
        resultPage.setRecords(followUsers);
        return resultPage;
    }

    @Override
    public List<Long> getMutualFriends(Long userId1, Long userId2) {
        // 使用MyBatis Plus的自定义SQL查询共同好友
        return userFollowMapper.selectMutualFriends(userId1, userId2);
    }

    @Override
    public boolean isFollowing(Long followerId, Long followingId) {
        return this.lambdaQuery()
                .eq(UserFollow::getFollowerId, followerId)
                .eq(UserFollow::getFollowingId, followingId)
                .eq(UserFollow::getDeleted, 0)
                .count() > 0;
    }

    // ==================== 课程点赞功能 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean likeCourse(Long userId, Long courseId) {
        // 使用MyBatis Plus检查是否已点赞
        long count = courseLikeMapper.selectCount(new LambdaQueryWrapper<CourseLike>()
                .eq(CourseLike::getUserId, userId)
                .eq(CourseLike::getCourseId, courseId)
                .eq(CourseLike::getDeleted, 0));

        if (count > 0) {
            return false;
        }

        try {
            // 1. 保存到数据库
            CourseLike like = CourseLike.builder()
                    .userId(userId)
                    .courseId(courseId)
                    .creator(userId)
                    .updater(userId)
                    .build();
            courseLikeMapper.insert(like);

            // 2. 更新Redis中的点赞关系
            updateRedisLikeRelation(userId, courseId, true);

            // 3. 更新计数器
            updateLikeCount(userId, courseId, 1);

            // 4. 更新点赞排行榜
            updateLikesLeaderboard(courseId);

            return true;
        } catch (Exception e) {
            log.error("点赞课程失败: {} -> {}", userId, courseId, e);
            throw new RuntimeException("点赞失败，请稍后重试");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean unlikeCourse(Long userId, Long courseId) {
        // 使用MyBatis Plus查找点赞记录
        CourseLike like = courseLikeMapper.selectOne(new LambdaQueryWrapper<CourseLike>()
                .eq(CourseLike::getUserId, userId)
                .eq(CourseLike::getCourseId, courseId)
                .eq(CourseLike::getDeleted, 0));

        if (like == null) {
            return false;
        }

        try {
            // 1. 逻辑删除
            like.setDeleted(1);
            like.setUpdater(userId);
            courseLikeMapper.updateById(like);

            // 2. 更新Redis中的点赞关系
            updateRedisLikeRelation(userId, courseId, false);

            // 3. 更新计数器
            updateLikeCount(userId, courseId, -1);

            // 4. 更新点赞排行榜
            updateLikesLeaderboard(courseId);

            return true;
        } catch (Exception e) {
            log.error("取消点赞课程失败: {} -> {}", userId, courseId, e);
            throw new RuntimeException("取消点赞失败，请稍后重试");
        }
    }

    @Override
    public boolean hasLikedCourse(Long userId, Long courseId) {
        return courseLikeMapper.selectCount(new LambdaQueryWrapper<CourseLike>()
                .eq(CourseLike::getUserId, userId)
                .eq(CourseLike::getCourseId, courseId)
                .eq(CourseLike::getDeleted, 0)) > 0;
    }

    @Override
    public IPage<Long> getLikedCourses(Long userId, IPage<Long> page) {
        // 使用MyBatis Plus的分页查询
        IPage<CourseLike> likePage = new Page<>(page.getCurrent(), page.getSize());

        likePage = courseLikeMapper.selectPage(likePage, new LambdaQueryWrapper<CourseLike>()
                .eq(CourseLike::getUserId, userId)
                .eq(CourseLike::getDeleted, 0)
                .orderByDesc(CourseLike::getCreateTime));

        if (likePage.getRecords().isEmpty()) {
            return new Page<>(page.getCurrent(), page.getSize());
        }

        List<Long> courseIds = likePage.getRecords().stream()
                .map(CourseLike::getCourseId)
                .collect(Collectors.toList());

        IPage<Long> resultPage = new Page<>(page.getCurrent(), page.getSize(), likePage.getTotal());
        resultPage.setRecords(courseIds);
        return resultPage;
    }

    @Override
    public IPage<Long> getCourseLikes(Long courseId, IPage<Long> page) {
        // 使用MyBatis Plus的分页查询
        IPage<CourseLike> likePage = new Page<>(page.getCurrent(), page.getSize());

        likePage = courseLikeMapper.selectPage(likePage, new LambdaQueryWrapper<CourseLike>()
                .eq(CourseLike::getCourseId, courseId)
                .eq(CourseLike::getDeleted, 0)
                .orderByDesc(CourseLike::getCreateTime));

        if (likePage.getRecords().isEmpty()) {
            return new Page<>(page.getCurrent(), page.getSize());
        }

        List<Long> userIds = likePage.getRecords().stream()
                .map(CourseLike::getUserId)
                .collect(Collectors.toList());

        IPage<Long> resultPage = new Page<>(page.getCurrent(), page.getSize(), likePage.getTotal());
        resultPage.setRecords(userIds);
        return resultPage;
    }

    @Override
    public Long getCourseLikeCount(Long courseId) {
        return courseLikeMapper.selectCount(new LambdaQueryWrapper<CourseLike>()
                .eq(CourseLike::getCourseId, courseId)
                .eq(CourseLike::getDeleted, 0));
    }

    // ==================== 工具方法 ====================

    private void updateRedisFollowRelation(Long currentUserId, Long targetUserId, boolean isFollow) {
        String followingKey = SocialRedisConfig.RedisKeys.USER_FOLLOWING + currentUserId;
        String followersKey = SocialRedisConfig.RedisKeys.USER_FOLLOWERS + targetUserId;

        if (isFollow) {
            socialStringRedisTemplate.opsForSet().add(followingKey, targetUserId.toString());
            socialStringRedisTemplate.opsForSet().add(followersKey, currentUserId.toString());
        } else {
            socialStringRedisTemplate.opsForSet().remove(followingKey, targetUserId.toString());
            socialStringRedisTemplate.opsForSet().remove(followersKey, currentUserId.toString());
        }
    }

    private void updateFollowCount(Long currentUserId, Long targetUserId, int delta) {
        String followingCountKey = SocialRedisConfig.RedisKeys.USER_FOLLOWING_COUNT + currentUserId;
        String followersCountKey = SocialRedisConfig.RedisKeys.USER_FOLLOWERS_COUNT + targetUserId;

        if (delta > 0) {
            socialStringRedisTemplate.opsForValue().increment(followingCountKey);
            socialStringRedisTemplate.opsForValue().increment(followersCountKey);
        } else {
            socialStringRedisTemplate.opsForValue().decrement(followingCountKey);
            socialStringRedisTemplate.opsForValue().decrement(followersCountKey);
        }
    }

    private void removeMutualFriend(Long userId, Long targetUserId) {
        String mutualKey = SocialRedisConfig.RedisKeys.USER_MUTUAL_FRIENDS + userId;
        socialStringRedisTemplate.opsForSet().remove(mutualKey, targetUserId.toString());
    }

    private void updateMutualFriends(Long userId1, Long userId2) {
        // 更新共同好友缓存
        String mutualKey1 = SocialRedisConfig.RedisKeys.USER_MUTUAL_FRIENDS + userId1;
        String mutualKey2 = SocialRedisConfig.RedisKeys.USER_MUTUAL_FRIENDS + userId2;

        // 添加到双方的共同好友集合中
        socialStringRedisTemplate.opsForSet().add(mutualKey1, userId2.toString());
        socialStringRedisTemplate.opsForSet().add(mutualKey2, userId1.toString());
    }

    private void updateRedisLikeRelation(Long userId, Long courseId, boolean isLike) {
        String likedUsersKey = SocialRedisConfig.RedisKeys.COURSE_LIKED_USERS + courseId;
        String userLikedCoursesKey = SocialRedisConfig.RedisKeys.USER_LIKED_COURSES + userId;

        if (isLike) {
            socialStringRedisTemplate.opsForSet().add(likedUsersKey, userId.toString());
            socialStringRedisTemplate.opsForSet().add(userLikedCoursesKey, courseId.toString());
        } else {
            socialStringRedisTemplate.opsForSet().remove(likedUsersKey, userId.toString());
            socialStringRedisTemplate.opsForSet().remove(userLikedCoursesKey, courseId.toString());
        }
    }

    private void updateLikeCount(Long userId, Long courseId, int delta) {
        String courseLikeCountKey = SocialRedisConfig.RedisKeys.COURSE_LIKE_COUNT + courseId;
        String userLikeCountKey = SocialRedisConfig.RedisKeys.USER_LIKE_COUNT + userId;

        if (delta > 0) {
            socialStringRedisTemplate.opsForValue().increment(courseLikeCountKey);
            socialStringRedisTemplate.opsForValue().increment(userLikeCountKey);
        } else {
            socialStringRedisTemplate.opsForValue().decrement(courseLikeCountKey);
            socialStringRedisTemplate.opsForValue().decrement(userLikeCountKey);
        }
    }

    private FollowUserDTO convertToFollowUserDTO(User user, UserFollow follow) {
        if (user == null) {
            return null;
        }

        FollowUserDTO dto = new FollowUserDTO();
        dto.setUserId(user.getId());
        dto.setUsername(user.getUsername());
        dto.setAvatar(user.getAvatar());
        dto.setBio(user.getBio());
        dto.setFollowTime(follow.getCreateTime());
        dto.setMutual(isFollowing(user.getId(), follow.getFollowerId()));
        dto.setFollowersCount(getUserFollowersCount(user.getId()));
        dto.setFollowingCount(getUserFollowingCount(user.getId()));
        return dto;
    }

    private Long getUserFollowingCount(Long userId) {
        return this.lambdaQuery()
                .eq(UserFollow::getFollowerId, userId)
                .eq(UserFollow::getDeleted, 0)
                .count();
    }

    private Long getUserFollowersCount(Long userId) {
        return this.lambdaQuery()
                .eq(UserFollow::getFollowingId, userId)
                .eq(UserFollow::getDeleted, 0)
                .count();
    }

    private void updateFollowingLeaderboard(Long userId) {
        String leaderboardKey = SocialRedisConfig.RedisKeys.FOLLOWING_LEADERBOARD;
        Long count = getUserFollowingCount(userId);
        socialStringRedisTemplate.opsForZSet().add(leaderboardKey, userId.toString(), count);
    }

    private void updateLikesLeaderboard(Long courseId) {
        String leaderboardKey = SocialRedisConfig.RedisKeys.LIKES_LEADERBOARD;
        Long count = getCourseLikeCount(courseId);
        socialStringRedisTemplate.opsForZSet().add(leaderboardKey, courseId.toString(), count);
    }

    @Override
    public UserStatsDTO getUserStats(Long userId) {
        UserStatsDTO stats = new UserStatsDTO();
        stats.setUserId(userId);

        // 获取关注数
        stats.setFollowingCount(getUserFollowingCount(userId));

        // 获取粉丝数
        stats.setFollowersCount(getUserFollowersCount(userId));

        // 获取获赞数（用户发布的所有课程的总点赞数）
        stats.setReceivedLikesCount(getUserTotalLikesReceived(userId));

        // 获取用户点赞的课程数
        stats.setLikedCoursesCount(getUserLikedCoursesCount(userId));

        return stats;
    }

    @Override
    public List<Long> getFollowingLeaderboard(int limit) {
        String leaderboardKey = SocialRedisConfig.RedisKeys.FOLLOWING_LEADERBOARD;
        Set<String> topUsers = socialStringRedisTemplate.opsForZSet()
                .reverseRange(leaderboardKey, 0, limit - 1);

        if (topUsers == null || topUsers.isEmpty()) {
            // 如果Redis中没有数据，从数据库查询
            return userFollowMapper.selectTopFollowingUsers(limit);
        }

        return topUsers.stream()
                .map(Long::valueOf)
                .collect(Collectors.toList());
    }

    @Override
    public List<Long> getLikesLeaderboard(int limit) {
        String leaderboardKey = SocialRedisConfig.RedisKeys.LIKES_LEADERBOARD;
        Set<String> topCourses = socialStringRedisTemplate.opsForZSet()
                .reverseRange(leaderboardKey, 0, limit - 1);

        if (topCourses == null || topCourses.isEmpty()) {
            // 如果Redis中没有数据，从数据库查询
            return courseLikeMapper.selectTopLikedCourses(limit);
        }

        return topCourses.stream()
                .map(Long::valueOf)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncRedisToDatabase() {
        log.info("开始同步Redis数据到数据库...");

        try {
            // 同步关注数据
            syncFollowDataToDatabase();

            // 同步点赞数据
            syncLikeDataToDatabase();

            log.info("Redis数据同步到数据库完成");
        } catch (Exception e) {
            log.error("同步Redis数据到数据库失败", e);
            throw new RuntimeException("数据同步失败");
        }
    }

    @Override
    public void loadDatabaseToRedis() {
        log.info("开始从数据库加载数据到Redis...");

        try {
            // 加载关注数据到Redis
            loadFollowDataToRedis();

            // 加载点赞数据到Redis
            loadLikeDataToRedis();

            log.info("从数据库加载数据到Redis完成");
        } catch (Exception e) {
            log.error("从数据库加载数据到Redis失败", e);
            throw new RuntimeException("数据加载失败");
        }
    }

    // ==================== 新增辅助方法 ====================

    private Long getUserTotalLikesReceived(Long userId) {
        // 这里假设用户有发布的课程，需要根据实际业务调整
        // 暂时返回0，后续根据实际业务需求实现
        return 0L;
    }

    private Long getUserLikedCoursesCount(Long userId) {
        return courseLikeMapper.selectCount(new LambdaQueryWrapper<CourseLike>()
                .eq(CourseLike::getUserId, userId)
                .eq(CourseLike::getDeleted, 0));
    }

    private void syncFollowDataToDatabase() {
        // 同步关注计数器
        Set<String> followingKeys = socialStringRedisTemplate.keys(
                SocialRedisConfig.RedisKeys.USER_FOLLOWING_COUNT + "*");
        if (followingKeys != null) {
            for (String key : followingKeys) {
                String userId = key.replace(SocialRedisConfig.RedisKeys.USER_FOLLOWING_COUNT, "");
                String countStr = socialStringRedisTemplate.opsForValue().get(key);
                if (countStr != null) {
                    Long count = Long.valueOf(countStr);
                    // 这里可以根据需要更新数据库中的计数
                }
            }
        }
    }

    private void syncLikeDataToDatabase() {
        // 同步点赞计数器
        Set<String> likeKeys = socialStringRedisTemplate.keys(
                SocialRedisConfig.RedisKeys.COURSE_LIKE_COUNT + "*");
        if (likeKeys != null) {
            for (String key : likeKeys) {
                String courseId = key.replace(SocialRedisConfig.RedisKeys.COURSE_LIKE_COUNT, "");
                String countStr = socialStringRedisTemplate.opsForValue().get(key);
                if (countStr != null) {
                    Long count = Long.valueOf(countStr);
                    // 这里可以根据需要更新数据库中的计数
                }
            }
        }
    }

    private void loadFollowDataToRedis() {
        // 加载所有有效的关注关系到Redis
        List<UserFollow> follows = this.lambdaQuery()
                .eq(UserFollow::getDeleted, 0)
                .list();

        for (UserFollow follow : follows) {
            updateRedisFollowRelation(follow.getFollowerId(), follow.getFollowingId(), true);
            updateFollowCount(follow.getFollowerId(), follow.getFollowingId(), 1);
        }
    }

    private void loadLikeDataToRedis() {
        // 加载所有有效的点赞关系到Redis
        List<CourseLike> likes = courseLikeMapper.selectList(
                new LambdaQueryWrapper<CourseLike>()
                        .eq(CourseLike::getDeleted, 0));

        for (CourseLike like : likes) {
            updateRedisLikeRelation(like.getUserId(), like.getCourseId(), true);
            updateLikeCount(like.getUserId(), like.getCourseId(), 1);
        }
    }
}